package com.lijinjiang.view;

import com.lijinjiang.beautyeye.ch3_button.BEButtonUI;
import jdk.nashorn.internal.parser.JSONParser;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.wav.WavFileReader;
import org.vosk.Model;
import org.vosk.Recognizer;

import javax.sound.sampled.AudioSystem;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.io.*;

/**
 * @ClassName MainFrame
 * @Description 主界面
 * @Author Li
 * @Date 2022/9/26 21:35
 * @ModifyDate 2022/9/26 21:35
 * @Version 1.0
 */
public class MainFrame {
    private JFrame mainFrame; // 主界面
    private final JPanel contentPanel = new JPanel(null); // 内容面板
    private String modelPath; // 模型位置
    private File chooseFile; // 选择的文件夹或文件
    private JTextField pathField; // 模型位置文本框
    private JTextField fileField; // 文件路径文本框
    private JTextArea displayArea; // 展示区域

    private JLabel timeLabel; // 显示耗时标签

    public MainFrame() {
        modelPath = System.getProperty("user.dir") + "/src/main/resources/vosk-model-small-cn-0.22"; // 初始化模型
        // System.out.println(modelPath);
        createFrame();
    }

    /**
     * 创建主窗口
     */
    private void createFrame() {
        mainFrame = new JFrame();
        mainFrame.setTitle("语音识别");
        createOperatePanel();
        createDisplayPane();
        createTimeLabel();
        mainFrame.add(contentPanel);
        mainFrame.setSize(new Dimension(800, 600));
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setLocationRelativeTo(null);
        mainFrame.setVisible(true);
    }

    /**
     * 创建操作面板
     */
    private void createOperatePanel() {
        JButton pathBtn = new JButton("选择模型");
        pathBtn.setLocation(10, 10);
        pathBtn.setSize(new Dimension(80, 36));
        pathBtn.setFocusable(false); // 不绘制焦点
        pathBtn.addActionListener(e -> showChoosePathDialog());


        pathField = new JTextField();
        pathField.setEditable(false);
        pathField.setLocation(100, 10);
        pathField.setSize(new Dimension(250, 36));


        JButton fileBtn = new JButton("选择文件");
        fileBtn.setFocusable(false); // 不绘制焦点
        fileBtn.addActionListener(e -> showChooseFileDialog());
        fileBtn.setLocation(360, 10);
        fileBtn.setSize(new Dimension(80, 36));


        fileField = new JTextField();
        fileField.setEditable(false);
        fileField.setLocation(450, 10);
        fileField.setSize(new Dimension(250, 36));

        // 开始执行按钮
        JButton startBtn = new JButton("执行");
        startBtn.addActionListener(e -> execute());
        startBtn.setUI(new BEButtonUI().setNormalColor(BEButtonUI.NormalColor.green));
        startBtn.setFocusable(false); // 不绘制焦点
        startBtn.setLocation(710, 10);
        startBtn.setSize(new Dimension(70, 36));


        contentPanel.add(pathBtn);
        contentPanel.add(pathField);
        contentPanel.add(fileBtn);
        contentPanel.add(fileField);
        contentPanel.add(startBtn);
    }

    /**
     * 创建展示面板
     */
    private void createDisplayPane() {
        JScrollPane scrollPane = new JScrollPane();
        displayArea = new JTextArea();
        scrollPane.setViewportView(displayArea);
        displayArea.setEditable(false);
        displayArea.setBorder(null);
        scrollPane.setSize(new Dimension(775, 480));
        scrollPane.setLocation(8, 56);
        contentPanel.add(scrollPane);
    }

    private void createTimeLabel() {
        timeLabel = new JLabel();
        timeLabel.setHorizontalAlignment(SwingConstants.RIGHT); // 文本靠右对齐
        timeLabel.setSize(new Dimension(100, 36));
        timeLabel.setLocation(680, 530);
        contentPanel.add(timeLabel);
    }

    /**
     * 选择模型位置
     */
    private void showChoosePathDialog() {
        JFileChooser fileChooser = new JFileChooser(); // 初始化一个文件选择器
        String pathValue = pathField.getText().trim();
        if (pathValue.length() == 0) {
            FileSystemView fsv = fileChooser.getFileSystemView(); // 获取文件系统网关
            fileChooser.setCurrentDirectory(fsv.getHomeDirectory()); // 设置桌面为当前文件路径
        } else {
            // 设置上一次选择路径为当前文件路径
            File file = new File(pathValue);
            File parentFile = file.getParentFile();
            if (parentFile == null) {
                fileChooser.setCurrentDirectory(file);
            } else {
                fileChooser.setCurrentDirectory(parentFile);
            }
        }
        fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); // 可选文件夹和文件
        fileChooser.setMultiSelectionEnabled(false); // 设置可多选
        int result = fileChooser.showOpenDialog(mainFrame);
        if (result == JFileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            modelPath = file.getAbsolutePath();
            pathField.setText(modelPath); // 将选择的文件路径写入到文本框
        }
    }

    /**
     * 选择需要转换成文字的文件夹或者文件
     * 文件夹：表示该目录下一层所有 wav 都需要转成文字
     * 文件：表示只需要将该文件转换成文字即可
     */
    private void showChooseFileDialog() {
        JFileChooser fileChooser = new JFileChooser(); // 初始化一个文件选择器
        String fileValue = fileField.getText().trim();
        if (fileValue.length() == 0) {
            FileSystemView fsv = fileChooser.getFileSystemView();
            fileChooser.setCurrentDirectory(fsv.getHomeDirectory()); // 设置桌面为当前文件路径
        } else {
            // 设置上一次选择路径为当前文件路径
            File file = new File(fileValue);
            File parentFile = file.getParentFile();
            if (parentFile == null) {
                fileChooser.setCurrentDirectory(file);
            } else {
                fileChooser.setCurrentDirectory(parentFile);
            }
        }
        fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); // 可选文件夹和文件
        fileChooser.setMultiSelectionEnabled(false); // 设置可多选
        fileChooser.removeChoosableFileFilter(fileChooser.getAcceptAllFileFilter()); // 不显示所有文件的下拉选
        fileChooser.addChoosableFileFilter(new FileNameExtensionFilter("wav", "wav"));
        int result = fileChooser.showOpenDialog(mainFrame);
        if (result == JFileChooser.APPROVE_OPTION) {
            chooseFile = fileChooser.getSelectedFile();
            fileField.setText(chooseFile.getAbsolutePath()); // 将选择的文件路径写入到文本框
        }
    }

    /**
     * 开始执行操作
     */
    private void execute() {
        displayArea.setText(""); // 执行后清空显示面板
        if (modelPath == null || 0 == modelPath.length()) {
            JOptionPane.showMessageDialog(mainFrame, "模型位置不能为空", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        if (chooseFile == null) {
            JOptionPane.showMessageDialog(mainFrame, "未选择文件夹或者音频文件", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        long startTime = System.currentTimeMillis();

        // 用于测试进度条的线程
        Thread thread = new Thread() {

            public void run() {
                if (chooseFile.isDirectory()) { // 如果是文件夹，则遍历里面每个文件
                    File[] files = chooseFile.listFiles(pathname -> pathname.getName().endsWith(".wav"));
                    if (files != null) {
                        for (File childFile : files) processFile(childFile);
                    }
                } else {
                    processFile(chooseFile);
                }

            }

        };
        //显示进度条测试对话框
        ProgressBar.show((Frame) null, thread, "语音正在识别中，请稍后...", "执行结束", "取消");
        // 否则直接处理该文件
        long endTime = System.currentTimeMillis();
        String msg = "耗时：" + (endTime - startTime) + "ms";
        timeLabel.setText(msg);
    }

    /**
     * 处理文件：语音转文字
     */
    private void processFile(File file) {
        try (Model model = new Model(modelPath);//该段是模型地址
             InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(file))); //该段是要转的语言文件，仅支持wav
             Recognizer recognizer = new Recognizer(model, getSampleRate(file))) { //该段中12000是语言频率(Hz)，需要大于8000，可以自行调整

            int bytes;
            byte[] b = new byte[4096];
            while ((bytes = ais.read(b)) >= 0) {
                recognizer.acceptWaveForm(b, bytes);
            }
            displayArea.append(file.getName() + " ");
            displayArea.append(recognizer.getFinalResult() + System.lineSeparator());
        } catch (Exception e) {
            JOptionPane.showMessageDialog(mainFrame, e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
            e.printStackTrace();
        }
    }

    /**
     * 获取音频文件的采样率
     */
    private Float getSampleRate(File file) throws Exception {
        WavFileReader fileReader = new WavFileReader();
        AudioFile audioFile = fileReader.read(file);
        String sampleRate = audioFile.getAudioHeader().getSampleRate();
        return Float.parseFloat(sampleRate);
    }
}
